package com.youzan.cloud.common.aspect;


import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.util.StringUtils;
import com.youzan.cloud.common.annotation.Signature;
import com.youzan.cloud.common.exception.AuthenticationFailExcetion;
import com.youzan.cloud.dataobject.SignatureConfig;
import com.youzan.cloud.service.SignatureConfigService;
import com.youzan.cloud.utils.DateUtil;
import com.youzan.cloud.utils.SignUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author tangsen233
 * @version 1.0
 * @description: 三方调用主动调用验签
 * @date 2021/11/16 15:36
 */
@Component
@Aspect
@Slf4j
public class SignatureAspect {
    @Autowired
    private SignatureConfigService signatureConfigService;

    @Before("@annotation(signature)")
    public void check(JoinPoint joinPoint, Signature signature) {
        //获取参数
        Object[] args = joinPoint.getArgs();
        JSONObject jsonObject = null;
        try {
            String param = JSONUtil.toJsonStr(args[0]);
            jsonObject = JSONUtil.parseObj(param);
            log.info("外部接口请求参数:{}", param);
        } catch (Exception e) {
            throw new AuthenticationFailExcetion("参数解析异常");
        }
        if (Objects.isNull(jsonObject)) {
            throw new AuthenticationFailExcetion("请求参数为空");
        }
        StringBuffer sb = new StringBuffer();
        String appId = jsonObject.getStr("appId");
        String sendTime = jsonObject.getStr("sendTime");
        String transactionId = jsonObject.getStr("transactionId");
        String sign = jsonObject.getStr("sign");
        if (StringUtils.isEmpty(sendTime) || StringUtils.isEmpty(appId) ||
                StringUtils.isEmpty(transactionId) || StringUtils.isEmpty(sign)) {
            throw new AuthenticationFailExcetion("验签必传参数不得为空");
        }
        long time = getTime(parse(sendTime), getStrDate());
        if (time > signature.exprieTime()) {
            throw new AuthenticationFailExcetion("超过调用时间");
        }
        SignatureConfig signatureConfig = signatureConfigService.selectConfigByAppId(appId);
        if (signatureConfig == null || StringUtils.isEmpty(signatureConfig.getAppSecret())) {
            throw new AuthenticationFailExcetion("未找到密钥");
        }
        String secret = signatureConfig.getAppSecret();
        //参数拼接
        String message = sb.append(transactionId).append(secret).append(appId).append(sendTime).toString();
        log.info("拼接的message:{}", message);
        String sha256Hmac = SignUtil.encryptSHA256Hmac(message, secret);
        log.info("生成的sign:{}", sha256Hmac + ",他们的sign{}:" + sign);
        if (!Objects.equals(sign, sha256Hmac)) {
            throw new AuthenticationFailExcetion("签名不一致");
        }
    }

    /**
     * @description: 获取系统当前时间，字符串类型
     * @param:
     * @return: java.util.Date
     * @author tangsen233
     */
    public static String getStrDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //设置为东八区
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        Date newDate = new Date();
        String dateStr = sdf.format(newDate);
        return dateStr;
    }

    /**
     * @param time yyyy-MM-dd hh:mm:ss.SSS格式时间
     * @return String  yyyy-MM-dd hh:mm:ss格式时间
     * @description: 时间转译
     * @version 1.0
     */
    public String parse(String time) {
        Date date = null;
        try {
            date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(time);
        } catch (ParseException e) {
            throw new AuthenticationFailExcetion("sendTime转换异常");
        }
        //定义新的字符串str将Date型转为String型
        String str = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(date);
        return str;
    }

    /**
     * @param oldTime 传入时间
     * @param newTime 当前时间
     * @return long 时间差值
     * @description: 获取两个时间相差分钟数
     * @version 1.0
     */
    public long getTime(String oldTime, String newTime) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long NTime = 0;
        long OTime = 0;
        try {
            NTime = df.parse(newTime).getTime();
            OTime = df.parse(oldTime).getTime();
        } catch (ParseException e) {
            throw new AuthenticationFailExcetion("sendTime转换异常");
        }
        long diff = (NTime - OTime) / 1000 / 60;
        return diff;
    }


}